﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using Hammock;
using Hammock.Authentication.OAuth;
using Hammock.Serialization;
using Hammock.Web;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Utility;
using WeiboPlus.Models;
using WeiboPlus.Service;
using WeiBoSdk;
using Q = WeiboPlus.Service.Web;
using WeiboPlus.Common;

namespace WeiboPlus.Renren
{
    public class RenrenStatusService : StatusServiceBase
    {
        //string _typeStatus = "10,11";
        //string _typeAll = "10,11,30,51";
        string _typeAll = "10,11,20,21,22,23,30,31,32,33,34,35,36,40,41,50,51,52,53,54,55";
        protected override void Initialize()
        {
            STATUS_HOME_TIMELINE = "restserver.do";
            STATUS_MENTIONS_TIMELINE = "";
        }

        public override void GetTimeline(SNSRequest snsRequest, Action<IList<SNSStatus>, SNSResult> action)
        {
            //base.GetTimeline(snsRequest, action);
            if (snsRequest.Type == SNSType.HomeStatus || snsRequest.Type == SNSType.CommentsByID || snsRequest.Type == SNSType.UserStatus)
            {
                var page = snsRequest.Parameters.FirstOrDefault(item => item.Name == SNSParametersConstants.PAGE);
                var count = snsRequest.Parameters.FirstOrDefault(item => item.Name == SNSParametersConstants.COUNT);

                var list = new List<Parameter>();

                list.Add(new Parameter("access_token", Account.AccessToken));
                if (snsRequest.Type == SNSType.HomeStatus)
                {
                    list.Add(new Parameter(SNSParametersConstants.METHOD, "feed.get"));
                    list.Add(new Parameter(SNSParametersConstants.TYPE, _typeAll));
                }
                else if (snsRequest.Type == SNSType.CommentsByID)
                {
                    var feed_type = snsRequest.Parameters.FirstOrDefault(item => item.Name == SNSParametersConstants.FEED_TYPE);

                    var status_id = snsRequest.Parameters.FirstOrDefault(item => item.Name == SNSParametersConstants.ROOTID);
                    var owner_id = snsRequest.Parameters.FirstOrDefault(item => item.Name == SNSParametersConstants.USER_ID);

                    switch (feed_type.Value)
                    {
                        case "10":
                        case "11":
                            list.Add(new Parameter(SNSParametersConstants.METHOD, "status.getComment"));

                            if (status_id != null)
                            {
                                list.Add(new Parameter(SNSParametersConstants.STATUS_ID, status_id.Value));
                            }
                            if (owner_id != null)
                            {
                                list.Add(new Parameter(SNSParametersConstants.OWNER_ID, owner_id.Value));
                            }
                            break;
                        case "20":
                        case "21":
                        case "22":
                        case "23":
                            list.Insert(0, new Parameter(SNSParametersConstants.METHOD, "blog.getComments"));
                            list.Insert(0, new Parameter(SNSParametersConstants.UID, owner_id.Value));
                            list.Insert(0, new Parameter(SNSParametersConstants.ID, status_id.Value));
                            break;
                        case "32":
                        case "33":
                        case "36":
                        case "50":
                        case "51":
                        case "52":
                        case "53":
                        case "54":
                        case "55":
                            list.Insert(0, new Parameter(SNSParametersConstants.METHOD, "share.getComments"));
                            list.Insert(0, new Parameter(SNSParametersConstants.USER_ID, owner_id.Value));
                            list.Insert(0, new Parameter(SNSParametersConstants.SHARE_ID, status_id.Value));
                            break;
                        case "30":
                        case "31":
                        default:
                            list.Insert(0, new Parameter(SNSParametersConstants.METHOD, "photos.getComments"));
                            list.Insert(0, new Parameter(SNSParametersConstants.UID, owner_id.Value));
                            list.Insert(0, new Parameter(SNSParametersConstants.PID, status_id.Value));
                            break;
                    }

                }
                else if (snsRequest.Type == SNSType.UserStatus)
                {
                    list.Add(new Parameter(SNSParametersConstants.METHOD, "status.get"));
                    //list.Add(new Parameter(SNSParametersConstants.TYPE, _typeAll));
                }

                list.Add(new Parameter(SNSParametersConstants.V, "1.0"));

                list.Add(new Parameter(SNSParametersConstants.FORMAT, "json"));
                if (page != null)
                    list.Add(new Parameter(SNSParametersConstants.PAGE, page.Value));
                else
                    list.Add(new Parameter(SNSParametersConstants.PAGE, "0"));
                if (count != null)
                    list.Add(new Parameter(SNSParametersConstants.COUNT, count.Value));
                else
                    list.Add(new Parameter(SNSParametersConstants.COUNT, "10"));
                var post = HttpRequestFactory.CreateHttpRequest(Method.POST) as HttpPost;
                int num = 0;
                post.AppSecret = Provider.AuthSettings.CONSUMER_KEY_SECRET;
                post.Request("http://api.renren.com/restserver.do", list, new AsyncRequestCallback((c, str) =>
                {
                    var result = new SNSResult() { IsSuccess = true, Message = "ok" };
                    var items = Mapping(str, result);

                    if (action != null)
                    {
                        action(items, result);
                    }
                }), out num);
            }
            else
            {
                action(null, new SNSResult() { IsSuccess = true, Message = "ok" });
            }
        }

        protected override RestClient CreateRestClient()
        {
            return new RestClient
            {
                Authority = "http://api.renren.com/",
                HasElevatedPermissions = true
            };
            //return base.CreateRestClient();
        }

        protected override RestRequest CreateRestRequest(SNSRequest snsRequest)
        {
            var req = base.CreateRestRequest(snsRequest);
            req.Method = WebMethod.Post;
            return req;
        }

        protected override string[] GetParamtersList(SNSType type)
        {
            switch (type)
            {
                case SNSType.HomeStatus:
                    return new string[] { SNSParametersConstants.METHOD, SNSParametersConstants.V, SNSParametersConstants.TYPE, SNSParametersConstants.FORMAT, SNSParametersConstants.PAGE, SNSParametersConstants.COUNT };
                case SNSType.Upload:
                    return new string[] { 
                        SNSParametersConstants.CAPTION,
                        SNSParametersConstants.UPLOAD
                        //SNSParametersConstants.BASE_APP
                    };
                case SNSType.AddStatus:
                    return new string[] { 
                        SNSParametersConstants.STATUS_TEXT
                        //SNSParametersConstants.BASE_APP
                    };
                case SNSType.RepostStatus:
                    return new string[] { 
                        SNSParametersConstants.STATUS,
                        SNSParametersConstants.FORWARD_ID,
                        SNSParametersConstants.FORWARD_OWNER
                        //SNSParametersConstants.BASE_APP
                    };
                case SNSType.AddComment:
                    return new string[] { 
                        SNSParametersConstants.SHARE_ID,
                        SNSParametersConstants.USER_ID,
                        SNSParametersConstants.CONTENT,
                        SNSParametersConstants.CALL_ID
                        //SNSParametersConstants.BASE_APP
                    };
                default:
                    return new string[] { };
            }
        }

        protected IList<SNSStatus> Mapping(string res)
        {
            List<SNSStatus> statuses = null;
            try
            {
                if (res.Contains("error"))
                {
                    //TODO HANDLE ERROR:
                    // Refresh / Notify user to refresh
                    return statuses;
                }

                JObject o = JObject.Parse("{\"statuses\":" + res + "}");

                statuses = o.SelectToken("statuses").Select(
                    s => Factory.GetMapping<JToken, SNSStatus>().Map(s)
                    ).ToList();
            }
            catch (Exception)
            {
                throw;
            }

            return statuses;
        }

        protected override IList<SNSStatus> Mapping(string res, SNSResult result)
        {
            List<SNSStatus> statuses = null;
            try
            {
                if (res.Contains("error") || string.IsNullOrEmpty(res))
                {
                    //TODO HANDLE ERROR:
                    // Refresh / Notify user to refresh
                    result = new SNSResult() { IsSuccess = false, Message = res };
                    return statuses;
                }
                JObject o = null;
                JToken t = null;
                if (res.StartsWith("["))
                {
                    o = JObject.Parse("{\"statuses\":" + res + "}");
                    t = o.SelectToken("statuses");
                }
                else
                {
                    o = JObject.Parse(res);
                    t = o.SelectToken("comments");
                }

                if (t != null && t.HasValues)
                    statuses = t.Select(
                        s => Factory.GetMapping<JToken, SNSStatus>().Map(s)
                        ).ToList();
            }
            catch (Exception ex)
            {
                result.IsSuccess = false;
                result.Message = ex.Message;
                return null;
            }

            return statuses;
        }

        protected override IList<T1> Mapping<T1>(string res, SNSResult result)
        {
            List<T1> statuses = null;
            try
            {
                if (res.Contains("error") || string.IsNullOrEmpty(res))
                {
                    //TODO HANDLE ERROR:
                    // Refresh / Notify user to refresh
                    result = new SNSResult() { IsSuccess = false, Message = res };
                    return statuses;
                }

                JObject o = JObject.Parse("{\"statuses\":" + res + "}");

                statuses = o.SelectToken("statuses").Select(
                    s => Factory.GetMapping<JToken, T1>().Map(s)
                    ).ToList();
            }
            catch (Exception ex)
            {
                result.IsSuccess = false;
                result.Message = ex.Message;
                return null;
            }

            return statuses;
        }

        protected override SNSStatus MappingSingle(string res, SNSResult result)
        {
            return base.MappingSingle(res, result);
        }

        public override void UpdateStatus(SNSRequest snsRequest, Action<SNSStatus, SNSResult> action)
        {
            var pList = GetParamtersList(snsRequest.Type);
            snsRequest.Predicate = (p) => pList.Contains(p.Name);

            var paras = new List<SNSParameter>(snsRequest.Parameters.Where(snsRequest.Predicate));

            paras.Insert(0, new SNSParameter("access_token", Account.AccessToken));
            paras.Insert(1, new SNSParameter("v", "1.0"));
            paras.Insert(2, new SNSParameter("format", "json"));

            var status = snsRequest.Parameters.First(item => item.Name == SNSParametersConstants.STATUS_TEXT).Value;

            var pic = snsRequest.Parameters.Where(p => p.Name == SNSParametersConstants.PIC).FirstOrDefault();
            if (pic == null)
            {
                paras.Insert(3, new SNSParameter(SNSParametersConstants.METHOD, "status.set"));
            }
            else
            {
                paras.Insert(0, new SNSParameter(SNSParametersConstants.METHOD, "photos.upload"));
            }

            if (!TryMappingMethodString(snsRequest))
            {
                //TO-DO
            }
            List<SNSParameter> file = null;

            int key = 0;
            if (paras.Any(p => p.Style == ParameterStyle.FilePath))
            {
                var files = paras.Where(p => p.Style == ParameterStyle.FilePath).ToList();
                foreach (var f in files)
                {
                    paras.Remove(f);
                }
                file = new List<SNSParameter>(files).ToList();
            }

            var request = new Q.QWeiboRequest();

            var r = request.BeginAsyncPost("http://api.renren.com/restserver.do", "POST", new Q.OauthKey(Provider.AuthSettings.CONSUMER_KEY, Provider.AuthSettings.CONSUMER_KEY_SECRET) { tokenKey = Account.AccessToken, tokenSecret = Account.AccessTokenSecret }, paras, file, (k, content) =>
            {
                try
                {
                    //var status = Mapping(str);
                    string msg;
                    int result = ValidateResponse(content, out msg);
                    if (result <= 0)
                    {
                        if (action != null)
                        {
                            action(null, new SNSResult() { IsSuccess = false, Message = msg });
                        }
                    }
                    if (action != null)
                    {
                        action(null, new SNSResult() { IsSuccess = true, Message = msg });
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    if (action != null)
                    {
                        action(null, new SNSResult() { IsSuccess = false, Message = ex.Message });
                    }
                }
            }, out key, SNSProviderType.RenRen);

            if (!r)
            {
                if (action != null)
                {
                    action(null, new SNSResult() { IsSuccess = false, Message = AppResx.ErrorOccured });
                }
            }
            //base.UpdateStatus(snsRequest, action);
        }

        private int ValidateResponse(string str, out string msg)
        {
            msg = "ok";
            JObject o = JObject.Parse(str);

            if (o.SelectToken("result") != null && (int)o.SelectToken("result") != 1)
            {
                msg = AppResx.ErrorOccured;
                return 0;
            }
            else if (o.SelectToken("error_msg") != null)
            {
                msg = (string)o.SelectToken("error_msg");
                return 0;
            }
            else
            {
                return 1;
            }
            //throw new NotImplementedException();
        }

        public override void QueryCounts(SNSRequest request, Action<SNSCounts, SNSResult> action)
        {
            //base.QueryCounts(request, action);
        }

        public override void ResetCounts(SNSRequest request, Action<SNSCounts, SNSResult> action)
        {
            //base.ResetCounts(request, action);
        }

        public override void AddComment(SNSRequest request, Action<SNSStatus, SNSResult> action)
        {
            //if (action != null)
            //{
            //    action(null, new SNSResult() { IsSuccess = false, Message = AppResx.NoSupportedBy+" RenRen" });
            //    return;
            //}

            //base.AddComment(request, action);
            var status = request.Status as Renren.RenrenSNSStatus;
            if (status == null)
            {
                action(null, new SNSResult() { IsSuccess = false, Message = AppResx.ErrorOccured });
                return;
            }

            var feed_type = status.FeedType.ToString();
            var content = request.Parameters.FirstOrDefault((p) => { return p.Name == SNSParametersConstants.CONTENT; });
            //var status_id = request.Parameters.FirstOrDefault((p) => { return p.Name == SNSParametersConstants.ID; });
            //var user_id = request.Parameters.FirstOrDefault((p) => { return p.Name == SNSParametersConstants.USER_ID; });
            var pList = GetParamtersList(request.Type);
            request.Predicate = (p) => pList.Contains(p.Name);

            var paras = new List<SNSParameter>();

            paras.Insert(0, new SNSParameter("access_token", Account.AccessToken));
            paras.Insert(1, new SNSParameter("v", "1.0"));
            paras.Insert(2, new SNSParameter("format", "json"));
            if (request.Type == SNSType.RepostStatus)
            {
                if (!string.IsNullOrEmpty(feed_type))
                {
                    switch (feed_type)
                    {
                        case "10":
                        case "11":

                            paras.Insert(0, new SNSParameter(SNSParametersConstants.METHOD, "status.forward"));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.FORWARD_OWNER, status.User.Id.ToString()));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.FORWARD_ID, status.Id.ToString()));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.STATUS, content.Value));
                            break;
                        case "30":

                            paras.Insert(0, new SNSParameter(SNSParametersConstants.METHOD, "share.share"));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.TYPE, "2"));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.USER_ID, status.User.Id.ToString()));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.UGC_ID, status.Id.ToString()));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.COMMENT, content.Value));
                            break;
                        case "51":
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.METHOD, "share.share"));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.TYPE, "20"));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.USER_ID, status.User.Id.ToString()));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.UGC_ID, status.Id.ToString()));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.COMMENT, content.Value));
                            break;
                        case "21":
                        case "23":
                        case "32":
                        case "33":
                        case "36":
                        case "50":
                        case "52":
                        case "53":
                        case "54":
                        case "55":
                        case "31":
                        default:
                            action(null, new SNSResult() { IsSuccess = false, Message = string.Format(AppResx.NoSupportedBy, "RenRen") });
                            return;
                    }
                }
            }
            else if (request.Type == SNSType.AddComment)
            {
                if (!string.IsNullOrEmpty(feed_type))
                {
                    switch (feed_type)
                    {
                        case "10":
                        case "11":
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.METHOD, "status.addComment"));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.OWNER_ID, status.User.Id.ToString()));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.STATUS_ID, status.Id.ToString()));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.CONTENT, content.Value));
                            break;
                        case "20":
                        case "21":
                        case "22":
                        case "23":
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.METHOD, "blog.addComment"));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.UID, status.User.Id.ToString()));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.ID, status.Id.ToString()));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.CONTENT, content.Value));
                            break;
                        case "32":
                        case "33":
                        case "36":
                        case "50":
                        case "51":
                        case "52":
                        case "53":
                        case "54":
                        case "55":
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.METHOD, "share.addComment"));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.USER_ID, status.User.Id.ToString()));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.SHARE_ID, status.Id.ToString()));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.CONTENT, content.Value));
                            break;
                        case "30":
                        case "31":
                        default:
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.METHOD, "photos.addComment"));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.UID, status.User.Id.ToString()));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.PID, status.Id.ToString()));
                            paras.Insert(0, new SNSParameter(SNSParametersConstants.CONTENT, content.Value));
                            break;
                    }
                }
            }

            int key = 0;

            var rq = new Q.QWeiboRequest();

            var r = rq.BeginAsyncPost("http://api.renren.com/restserver.do", "POST", new Q.OauthKey(Provider.AuthSettings.CONSUMER_KEY, Provider.AuthSettings.CONSUMER_KEY_SECRET) { tokenKey = Account.AccessToken, tokenSecret = Account.AccessTokenSecret }, paras, null, (k, rcontent) =>
            {
                try
                {
                    //var status = Mapping(str);
                    string msg;
                    int result = ValidateResponse(rcontent, out msg);
                    if (result <= 0)
                    {
                        if (action != null)
                        {
                            action(null, new SNSResult() { IsSuccess = false, Message = msg });
                        }
                    }
                    else if (action != null)
                    {
                        var s = new SNSStatus() { Text = content.Value, User = Account.UserLite, CreatedTime = DateTime.Now };
                        action(s, new SNSResult() { IsSuccess = true, Message = msg });
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    if (action != null)
                    {
                        action(null, new SNSResult() { IsSuccess = false, Message = ex.Message });
                    }
                }
            }, out key, SNSProviderType.RenRen);

            if (!r)
            {
                if (action != null)
                {
                    action(null, new SNSResult() { IsSuccess = false, Message = AppResx.ErrorOccured });
                }
            }
        }
    }
}
